﻿///////////////////////////////////////////////////////////////////////////////
//
// wxFormBuilder - A Visual Dialog Editor for wxWidgets.
// Copyright (C) 2005 José Antonio Hurtado
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// Written by
//   José Antonio Hurtado - joseantonio.hurtado@gmail.com
//   Juan Antonio Ortega  - jortegalalmolda@gmail.com
//
///////////////////////////////////////////////////////////////////////////////

#ifndef __OBJ_DATABASE__
#define __OBJ_DATABASE__

#include "../utils/wxfbdefs.h"
#include "types.h"
#include <QBitmap>
#include <set>
#include <vector>
#include <QString> 


class ObjectDatabase;
class ObjectTypeDictionary;
class PropertyCategory;

typedef std::shared_ptr<ObjectDatabase> PObjectDatabase;

namespace ticpp {
class Element;
}

/**
 * Paquete de clases de objetos.
 * Determinará la agrupación en la paleta de componentes.
 */
class ObjectPackage {
private:
	QString m_name; // nombre del paquete
	QString m_desc; // breve descripción del paquete
	QBitmap m_icon; // The icon for the notebook page

	// Vector con los objetos que están contenidos en el paquete
	std::vector<PObjectInfo> m_objs;

public:
	/**
	 * Constructor.
	 */
	ObjectPackage(QString name, QString desc, QBitmap icon);

	/**
	 * Incluye en el paquete la información de un objeto.
	 */
	void Add(PObjectInfo obj) {
		m_objs.push_back(obj);
	}

	/**
	 * Obtiene el nombre del paquete.
	 */
	QString GetPackageName() {
		return m_name;
	}

	/**
	 * Obtiene el texto que describe el paquete.
	 */
	QString GetPackageDescription() {
		return m_desc;
	}

	/**
	 * Get Package Icon
	 */
	QBitmap GetPackageIcon() {
		return m_icon;
	}

	/**
	 * Obtiene el número de objetos incluidos en el paquete.
	 */
	unsigned int GetObjectCount() {
		return (unsigned int)m_objs.size();
	}

	/**
	 * Obtiene la información de un objeto incluido en el paquete.
	 */
	PObjectInfo GetObjectInfo(unsigned int idx);

	/**
	If two xml files specify the same package name, then they merged to one package with this.
	This allows one package to be split across multiple xml files.
	*/
	void AppendPackage(PObjectPackage package);
};


/**
 * Base de datos de objetos.
 * Todos las informaciones de objetos importadas de los archivos XML, serán
 * almacenados por esta clase.
 */
class ObjectDatabase {
public:
	static bool HasCppProperties(QString type);

private:
	typedef std::vector<PObjectPackage> PackageVector;

	// Map the property type string to the property type number
	typedef std::map<QString, PropertyType> PTMap;
	typedef std::map<QString, PObjectType> ObjectTypeMap;

	typedef std::set<QString> MacroSet;
	typedef std::map<QString, PCodeInfo> LangTemplateMap;
	typedef std::map<PropertyType, LangTemplateMap> PTLangTemplateMap;

	QString m_xmlPath;
	QString m_iconPath;
	QString m_pluginPath;
	std::map<QString, PObjectInfo> m_objs;
	PackageVector m_pkgs;
	PTMap m_propTypes;
	ObjectTypeMap m_types; // register object types

	// para comprobar que no se nos han quedado macros sin añadir en las
	// liberias de componentes, vamos a crear un conjunto con las macros
	// definidas en los XML, y al importar las librerías vamos a ir eliminando
	// dichas macros del conjunto, quedando al final las macros que faltan
	// por registrar en la librería.
	MacroSet m_macroSet;


	PTLangTemplateMap m_propertyTypeTemplates;

    // lcd templates
    std::vector<PLcdTemplateInfo>  m_lcdTemplates;
	/**
	 * Initialize the property type map.
	 */
	void InitPropertyTypes();

	/**
	 * Carga las plantillas de generación de código de un fichero
	 * xml de código dado
	 */
	void LoadCodeGen(const QString& file);

	/**
	 * Carga los objetos de un paquete con todas sus propiedades salvo
	 * los objetos heredados
	 */
    PObjectPackage LoadPackage(const QString& file, const QString& iconPath);

	void ParseProperties(ticpp::Element* elem_obj, PObjectInfo obj_info, PPropertyCategory category,
	                     std::set<PropertyType>* types);
    void ParseProperties(ticpp::Element* elem_obj, PLcdTemplateInfo obj_info, std::set<PropertyType>* types);
	void ParseEvents(ticpp::Element* elem_obj, PObjectInfo obj_info, PPropertyCategory category);

  void LoadLcdTemplates(const QString& file);

	/**
	 * Incluye la información heredada de los objetos de un paquete.
	 * En la segunda pasada configura cada paquete con sus objetos base.
	 */
	void SetupPackage(const QString& file, const QString& path, PwxFBManager manager);

	/**
	 * Determina si el tipo de objeto hay que incluirlo en la paleta de
	 * componentes.
	 */
	bool ShowInPalette(QString type);

	// rutinas de conversión
	PropertyType ParsePropertyType(QString str);
	QString ParseObjectType(QString str);

	PObjectType GetObjectType(QString name);

	int CountChildrenWithSameType(PObjectBase parent, PObjectType type);
	int CountChildrenWithSameType(PObjectBase parent, const std::set<PObjectType>& types);

	void SetDefaultLayoutProperties(PObjectBase obj);

public:
	ObjectDatabase();
	~ObjectDatabase();

	PObjectBase NewObject(PObjectInfo obj_info);

	/**
	 * Obtiene la información de un objeto a partir del nombre de la clase.
	 */
	PObjectInfo GetObjectInfo(QString class_name);

	/**
	 * Configura la ruta donde se encuentran los ficheros con la descripción.
	 */
	void SetXmlPath(const QString& path) {
		m_xmlPath = path;
	}

	/**
	 * Configura la ruta donde se encuentran los iconos asociados a los objetos.
	 */
	void SetIconPath(const QString& path) {
		m_iconPath = path;
	}

	/**
	 * Obtiene la ruta donde se encuentran los ficheros con la descripción de
	 * objetos.
	 */
	QString GetXmlPath() {
		return m_xmlPath;
	}
	QString GetIconPath() {
		return m_iconPath;
	}
	QString GetPluginPath() {
		return m_pluginPath;
	}

	/**
	 * Carga las definiciones de tipos de objetos.
	 */
	bool LoadObjectTypes();

	/**
	 * Find and load plugins from the plugins directory
	 */
	void LoadPlugins(PwxFBManager manager);

	/**
	 * Fabrica de objetos.
	 * A partir del nombre de la clase se crea una nueva instancia de un objeto.
	 */
	PObjectBase CreateObject(std::string class_name, PObjectBase parent = PObjectBase());

	/**
	 * Fábrica de objetos a partir de un objeto XML.
	 * Este método se usará para cargar un proyecto almacenado.
	 */
	PObjectBase CreateObject(ticpp::Element* obj, PObjectBase parent = PObjectBase());

	/**
	 * Crea un objeto como copia de otro.
	 */

	PObjectBase CopyObject(PObjectBase obj);

	/**
	 * Obtiene un paquete de objetos.
	 */
	PObjectPackage GetPackage(unsigned int idx);

	/**
	 * Obtiene el número de paquetes registrados.
	 */
	unsigned int GetPackageCount() {
		return (unsigned int)m_pkgs.size();
	}

	/**
	 * Resetea los contadores que acompañan al nombre.
	 * La propiedad "name" es una propiedad especial, reservada para el nombre
	 * de la instancia del objeto. Cada clase de objeto tiene asociado un contador
	 * para no duplicar nombre en la creación de nuevos objetos
	 * (p.e. m_button1, m_button2 ...)
	 */
	void ResetObjectCounters();

	std::vector<PLcdTemplateInfo> & GetPLcdTemplateInfos(){ return m_lcdTemplates;};
};

#endif //__OBJ_DATABASE__
